package com.xiaoji.authface.service;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xiaoji.authface.repository.UserRepository;
import com.xiaoji.authface.utils.GsonUtils;
import com.xiaoji.authface.utils.HttpUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baidu.aip.face.AipFace;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 权限认证服务: 获取token类
 *  向百度API服务地址发送POST请求
 */

@Service
public class FaceService implements IFaceService {

    // AppID
    private static final String AppID = "24970557";
    // API KEY
    private static final String AK = "KtUMfpceHyNGHr1QXj7qIU4Y";
    // Secret Key
    private static final String SK = "5mVnxvPkIbAkdk3bPSEoabIklDWTc6LC";


    /**
     *  @ Autowired
     *  this means to get the bean called userRepository
     *  which is auto-generated by Spring, we will use it to handle the data
     */
    @Autowired  // Field injection is not recommended
    private UserRepository userRepository;


    /**
     * 人脸识别登录
     * @param faceBase64 本地人脸数据
     * @return 返回判断结果
     */
    @Override
    public String faceLogin(String faceBase64) {

        Double score = faceMatch(faceBase64);

        if(score > 95){
            System.out.println(score);
//            System.out.println("Face Login Score:" + score);
            return "SUCCESS";
        }else{
            return "FAIL";
        }
    }

    /***
     * 人脸注册
     * @param name 图片信息，人物姓名
     * @param faceBase64 人脸base64格式
     */
    @Override
    public String faceRegister(String user_id, String name, String faceBase64) {
        // 人脸检测，返回face_token, age, emotion
        String str = faceDetect(faceBase64);
        // 解析json,获取face_token
        String face_token = getFaceToken(str);
        // 人脸注册
        String group_id = "Aising";  // 默认用户组

       return faceAdd(group_id, user_id, name, face_token);
    }




    // main test
    public static void main(String[] args) {
        // getAuth Test
        System.out.println(getAuth());

        // face_token Test
        String faceDetectRes = "{\"error_code\":0,\"error_msg\":\"SUCCESS\",\"log_id\":3575947579058,\"timestamp\":1634438600,\"cached\":0,\"result\":{\"face_num\":1,\"face_list\":[{\"face_token\":\"00c9bd4f9311e78bc8b726533183997c\",\"location\":{\"left\":129.38,\"top\":74.36,\"width\":85,\"height\":61,\"rotation\":-1},\"face_probability\":1,\"angle\":{\"yaw\":-2.73,\"pitch\":10.7,\"roll\":-5.17},\"age\":23,\"emotion\":{\"type\":\"happy\",\"probability\":0.79}}]}}";
        System.out.println(getFaceToken(faceDetectRes));

        // face match test --- 获取score
        String faceMatchRes = "{\"result\":{\"face_token\":\"43bbb996defbe2b9f99311e6fad5721b\",\"user_list\":[{\"score\":96.288429260254,\"group_id\":\"Aising\",\"user_id\":\"36\",\"user_info\":\"baiduyunFaceTest\"}]},\"log_id\":2016589101051,\"error_msg\":\"SUCCESS\",\"cached\":0,\"error_code\":0,\"timestamp\":1634442470}";
        System.out.println(getScoreFromFaceMatch(faceMatchRes));
    }

    /**
     * 获取API访问token
     * 该token有一定的有效期，需要自行管理，当失效时需重新获取.
     * ak - 百度云官网获取的 API Key
     * sk - 百度云官网获取的 Securet Key
     * @return assess_token 示例：
     * "24.460da4889caad24cccdb1fea17221975.2592000.1491995545.282335-1234567"
     */
    private static String getAuth() {
        // 获取token地址
        String authHost = "https://aip.baidubce.com/oauth/2.0/token?";
        String getAccessTokenUrl = authHost
                // 1. grant_type为固定参数
                + "grant_type=client_credentials"
                // 2. 官网获取的 API Key
                + "&client_id=" + AK
                // 3. 官网获取的 Secret Key
                + "&client_secret=" + SK;
        try {
            URL realUrl = new URL(getAccessTokenUrl);
            // 打开和URL之间的连接
            HttpURLConnection connection = (HttpURLConnection) realUrl.openConnection();
            connection.setRequestMethod("GET");
            connection.connect();
            // 获取所有响应头字段
            Map<String, List<String>> map = connection.getHeaderFields();
            // 遍历所有的响应头字段
            for (Object key : ((Map<?, ?>) map).keySet()) {
                System.err.println(key + "--->" + map.get(key));
            }
            // 定义 BufferedReader输入流来读取URL的响应
            BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            StringBuilder result = new StringBuilder();
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }

            /**
             * 返回结果示例
             */
            System.err.println("result:" + result);
            JSONObject jsonObject = new JSONObject();
            jsonObject = JSON.parseObject(result.toString());
            return jsonObject.getString("access_token");

        } catch (Exception e) {
            System.err.print("获取token失败！");
            e.printStackTrace(System.err);
        }
        return null;
    }


    /**
     * 人脸检测，返回face_token: 人脸的唯一标识，为人脸注册做准备
     * @param faceBase64 人脸的base64编码
     * @return face_tocken
     */
    private static String faceDetect(String faceBase64){

        // 请求url
        String url = "https://aip.baidubce.com/rest/2.0/face/v3/detect";
        try {
            Map<String, Object> map = new HashMap<>();
            map.put("image", faceBase64);
            map.put("face_field", "age,emotion"); // 默认只返回face_token
            map.put("image_type", "BASE64");

            String param = GsonUtils.toJson(map);

            // 注意这里仅为了简化编码每一次请求都去获取access_token，线上环境access_token有过期时间， 客户端可自行缓存，过期后重新获取。
            String accessToken = getAuth();
//            System.out.println("token: " + accessToken);

            return HttpUtil.post(url, accessToken, "application/json", param);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }



    /**
     * 从faceDetect返回的json数据中解析出face_token
     * @param faceDetectRes
     * @return
     */
    /**
     * {
     *   "error_code":0,
     *   "error_msg":"SUCCESS",
     *   "log_id":4535201752012,
     *   "timestamp":1634437681,
     *   "cached":0,
     *   "result":
     *   {
     *     "face_num":1,
     *     "face_list":[
     *       {
     *         "face_token":"f9b80fcb787e9f1852812918f8905b84",
     *         "location":{"left":124.44,"top":67.11,"width":87,"height":63,"rotation":0},
     *         "face_probability":1,
     *         "angle":{"yaw":-9.07,"pitch":12.58,"roll":-1.43},
     *         "age":23,
     *         "emotion":{"type":"happy","probability":0.78}
     *       }
     *     ]
     *   }
     * }
     */
    private static String getFaceToken(String faceDetectRes){
        // [1] 转成json数据
        JSONObject faceResult = new JSONObject();
        faceResult = JSON.parseObject(faceDetectRes);
        // [2] 提取result数据
        JSONObject result = faceResult.getJSONObject("result");
        //[3] 注意：face_list中的内容带有中括号[]，所以要转化为JSONArray类型的对象
        JSONArray face_list = result.getJSONArray("face_list");
        // [4] 获取face_token
        return face_list.getJSONObject(0).getString("face_token");
    }


    /**
     * 人脸注册
     * @param group_id 用户组，可以自己创建，一个用户可以有多个
     * @param user_id 每个用户组，可添加无限个user_id,无限张脸，每个用户(user_id)所能注册的最大人脸数量是20
     * @param user_info 用户描述信息 name
     * @param face_token face_token
     * @return log_id 请求标识码；face_token人脸图片唯一标识，location人脸在图片中的位置
     */
    private static String faceAdd(String group_id, String user_id, String user_info, String face_token){

        // 请求url
        String url = "https://aip.baidubce.com/rest/2.0/face/v3/faceset/user/add";
        try {
            Map<String, Object> map = new HashMap<>();
            map.put("image", face_token);
            map.put("group_id",group_id);
            map.put("user_id", user_id);
            map.put("user_info", user_info);
            map.put("liveness_control", "NORMAL");
            map.put("image_type", "FACE_TOKEN");
            map.put("quality_control", "LOW");

            String param = GsonUtils.toJson(map);

            // 注意这里仅为了简化编码每一次请求都去获取access_token，线上环境access_token有过期时间， 客户端可自行缓存，过期后重新获取。
            String accessToken = getAuth();
            // System.out.println(result);

            return HttpUtil.post(url, accessToken, "application/json", param);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 人脸比对
     * @param faceBase64 本地采集人脸数据
     * @return 相似度
     */
    private static Double faceMatch(String faceBase64){
        // 请求url
        // String url = "https://aip.baidubce.com/rest/2.0/face/v3/match";

        // client 客户端数据
        AipFace client = new AipFace(AppID, AK, SK);
        // 传入可选参数调用接口
        HashMap<String, String> options = new HashMap<>();
        org.json.JSONObject res = client.search(faceBase64, "BASE64", "Aising", options);
        // 提取score
        return getScoreFromFaceMatch(res.toString());
}

    /**
     * 从faceMatch返回的结果中提取score
     * @param faceMatchRes 返回结果
     * @return score
     */
    private static Double getScoreFromFaceMatch(String faceMatchRes){
        JSONObject jsonFaceMatch = new JSONObject();
        jsonFaceMatch = JSON.parseObject(faceMatchRes);
        JSONObject user = (JSONObject) jsonFaceMatch.getJSONObject("result").getJSONArray("user_list").get(0);
        return user.getDouble("score");
    }

}


